/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.kamismile.stone.rpc.core.proxy.imp.bytebuddy;


import com.gitee.kamismile.stone.rpc.api.invocation.support.StoneInvocation;
import com.gitee.kamismile.stone.rpc.api.invocation.support.StoneInvocationFactory;
import com.gitee.kamismile.stone.rpc.common.invocation.StoneInvocationType;
import com.gitee.kamismile.stone.rpc.common.support.StoneURL;
import com.gitee.kamismile.stone.rpc.core.invocation.StoneInvokeInvoker;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.Super;
import net.bytebuddy.implementation.bind.annotation.This;
import  org.slf4j.LoggerFactory;
import org.slf4j.Logger;

import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;

/**
 * @author bystander
 * @version $Id: BytebuddyInvocationHandler.java, v 0.1 2019年01月30日 12:31 bystander Exp $
 */
public class BytebuddyInvocationHandler {

    protected static final Logger logger = LoggerFactory.getLogger(BytebuddyInvocationHandler.class);


    private StoneInvokeInvoker stoneInvokeInvoker;

    public BytebuddyInvocationHandler(StoneInvokeInvoker stoneInvokeInvoker) {
        this.stoneInvokeInvoker = stoneInvokeInvoker;
    }

    @RuntimeType
    public Object byteBuddyInvoke(@Super Object proxy,@Origin Method method, @AllArguments Object[] args)
            throws Throwable {
        String methodName = method.getName();
        if ("equals".equals(methodName)) {
            Object another = args[0];
            return proxy == another ||
                    (proxy.getClass().isInstance(another));
        } else if ("hashCode".equals(methodName)) {
            return stoneInvokeInvoker.hashCode();
        } else if ("toString".equals(methodName)) {
            return stoneInvokeInvoker.toString();
        }


        Class<?>[] parameterTypes = method.getParameterTypes();

        StoneInvocation invocation = StoneInvocationFactory.createInvocation(stoneInvokeInvoker.getMapperInterface(), method, stoneInvokeInvoker.getStoneURL(), StoneInvocationType.PRODUCER);

        StoneURL stoneURL = invocation.getStoneURL();
        stoneURL.setMethodName(methodName);
        stoneURL.setParameterTypes(parameterTypes);
        stoneURL.setArguments(args);

        invocation.setServerName(stoneInvokeInvoker.getServerName());
        invocation.setServerVersion(stoneInvokeInvoker.getServerVersion());
        invocation.setTimeout(stoneInvokeInvoker.getTimeout());
        if (CompletableFuture.class.equals(method.getReturnType())) {
            return stoneInvokeInvoker.completableFutureInvoke(invocation);
        }

        return stoneInvokeInvoker.syncInvoke(invocation);

    }
}